package com.google.code.mc4java;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import com.google.code.mc4java.conn.AbstractConnection;
import com.google.code.mc4java.conn.ConnectionManager;
import com.google.code.mc4java.msg.Command;
import com.google.code.mc4java.msg.TextMessage;

public class SaeMemcachexClient {
	
	private static final String STORED = "STORED";		// successful store of data
	@SuppressWarnings("unused")
	private static final String NOTSTORED = "NOT_STORED";	// data not stored
	
	@SuppressWarnings("unused")
	private static final String VALUE = "VALUE";
	private static final String END = "END";
	
	private List<ServerInfo> serverInfo = new ArrayList<ServerInfo>();
	
    /**
     * CR.
     */
    public static final byte CR = (byte) '\r';


    /**
     * LF.
     */
    public static final byte LF = (byte) '\n';
	
	public SaeMemcachexClient(String ip,int port)throws IOException {
		ServerInfo info = new ServerInfo();
		info.ip = ip;
		info.port = port;
		this.serverInfo.add(info);
		init();
	}
	
	public SaeMemcachexClient(List<SaeMemcachexClient.ServerInfo> list)throws IOException {
		serverInfo.addAll(list);
		init();
	}
	
	private void init() throws IOException {
		for(int i=0;i<serverInfo.size();i++) {
			ServerInfo si = serverInfo.get(i);
			ConnectionManager.getInstance().addServer(si);
		}
		ConnectionManager.getInstance().init();
	}
	
	
	public boolean set(String key,Object value) throws IOException {
		AbstractConnection conn = ConnectionManager.getInstance().getConnection(key);
		TextMessage tm = new TextMessage(); 
		tm.createMessage(key, value, 0, Command.SET);
		conn.send(tm);
		String line = conn.readLine();
		if(STORED.equals(line)) {
			return true;
		}
		return false;
	}

	
	@SuppressWarnings("unchecked")
	public <T> T get(String key)throws IOException {
		AbstractConnection conn = ConnectionManager.getInstance().getConnection(key);
		TextMessage tm = new TextMessage();
		tm.createMessage(key,Command.GET);
		conn.send(tm);
		String line = conn.readLine();
		String[] result = line.split(" ");
		
		int flag = Integer.parseInt(result[result.length-2]);
		int len = Integer.parseInt(result[result.length-1]);
		byte[] buf = conn.receive(len);
		conn.skipEnter();
		Object val = tm.parseMessage(flag, buf);
		
		line = conn.readLine();
		if(END.equals(line)) {
			return (T)val;
		} else {
			return null;
		}
		
	}
	
/*

		
		SocketChannel socket = socketList.get(0);
		ByteArrayOutputStream bos = new ByteArrayOutputStream();
		ObjectOutputStream oos = new ObjectOutputStream(bos);
		oos.writeObject(value);
		byte[] objBytes = bos.toByteArray();
		int objLength = objBytes.length;

		
		String cmd = String.format("%s %s %d %d %d\r\n", "set", key, 0, 0, objLength);
		byte[] cmdBytes = cmd.getBytes();
		
		ByteArrayOutputStream baos = new ByteArrayOutputStream();
		baos.write(cmdBytes);
		baos.write(objBytes);
		baos.write("\r\n".getBytes());
		byte[] baosBuytes = baos.toByteArray();
		ByteBuffer bb = ByteBuffer.allocate(baosBuytes.length);
		bb.put(baosBuytes);
		bb.flip();
		socket.write(bb);
		
		bb.clear();
		socket.read(bb);
		
		byte[] result = bb.array();
		int pos = 0;
		for(int i=0;i<result.length;i++) {
			if(result[i] == CR) {
				if(result[i+1] == LF) {
					pos = i;
					break;
				}
			}
		}
		String resultVal = new String(result,0,pos);
		if(STORED.equals(resultVal)) {
			return true;
		}
		return false;


 */
	
	
/*
	public Object get(String key)throws IOException {
		SocketChannel socket = socketList.get(0);
		ByteArrayOutputStream baos = new ByteArrayOutputStream();
		baos.write(("get "+key+" \r\n").getBytes());
		byte[] cmdBytes = baos.toByteArray();
		ByteBuffer bb = ByteBuffer.allocate(cmdBytes.length);
		socket.write(bb);

		
		bb = ByteBuffer.allocate(VALUE.length()+key.length()+4);
		ByteBuffer b1 = ByteBuffer.allocate(1);
		
		socket.configureBlocking(true);
		InputStream is = socket.socket().getInputStream();
		ByteArrayOutputStream bos = new ByteArrayOutputStream();
		byte[] b = new byte[1];
		boolean eol = false;
		while ( is.read( b, 0, 1 ) != -1 ) {

			if ( b[0] == 13 ) {
				eol = true;
			}
			else {
				if ( eol ) {
					if ( b[0] == 10 )
						break;

					eol = false;
				}
			}
			bos.write( b, 0, 1 );
		}		
		String line = bos.toString().trim();
		System.out.println(line);
		
		
		return null;
	}
*/	
	
	public static class ServerInfo {
		private String ip;
		private int port;
		public String getIp() {
			return ip;
		}
		public void setIp(String ip) {
			this.ip = ip;
		}
		public int getPort() {
			return port;
		}
		public void setPort(int port) {
			this.port = port;
		}
	}
}
